﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Linq;
using Soleil.Domain.Core.DomainObjects;
using Soleil.Domain.Core.Repositories;

namespace Infrastructure.Data.NH.Core.Repositories
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : DomainObject
    {
        public NHUnitOfWork UnitOfWork { get; private set; }

        public Repository ()
        {
            UnitOfWork = new NHUnitOfWork();
        }


        #region Implementation of IRepository<TEntity>


        public bool Add(TEntity entity)
        {
            UnitOfWork.DbContext.Save(entity);
            return true;
        }

        public bool Add(IEnumerable<TEntity> entities)
        {
            //entities.ForEach(entity => session.Save(entity));
            return true;
        }

        public bool Update(TEntity entity)
        {
            UnitOfWork.DbContext.Update(entity);
            //session.SaveOrUpdate(entity);
            //session.Flush();

            return true;
        }

        public bool Delete(TEntity entity)
        {
            UnitOfWork.DbContext.Delete(entity);
            return true;
        }

        public bool Delete(IEnumerable<TEntity> entities)
        {
            //entities.ForEach(entity => session.Delete(entity));
            return true;
        }

        public IQueryable<TEntity> All()
        {
            return UnitOfWork.DbContext.Query<TEntity>();
        }

        public bool Exists(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, int>> selectExpression)
        {
            return !All().Where(expression).Select(selectExpression).SingleOrDefault().Equals(default(int));
        }

        public IList<TEntity> GetAll()
        {
            return All().ToList();
        }

        public TEntity FindBy(Expression<Func<TEntity, bool>> expression)
        {
            return FilterBy(expression).SingleOrDefault();
        }

        public int FindKeyBy(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, int>> selectExpression)
        {
            return All().Where(expression).Select(selectExpression).SingleOrDefault();
        }



        public bool TryFindBy(ref TEntity result, Expression<Func<TEntity, bool>> expression)
        {
            try
            {
                result = FindBy(expression);
                if (result == null)
                    throw new Exception();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression)
        {
            return All().Where(expression).AsQueryable();
        }

        public void LoadProperty(object ownerObject, object property)
        {
            // Connecting the object to the seesion
            if (UnitOfWork.DbContext.Contains(ownerObject) == false)
            {
                UnitOfWork.DbContext.Lock(ownerObject, LockMode.None);
            }

            NHibernateUtil.Initialize(property);
        }

        public void Dispose()
        {
            if (UnitOfWork != null)
            {
                UnitOfWork.Dispose();
            }
        }

        #endregion

        #region Implementation of IKeyedRepository<TKey,TEntity>

        public TEntity FindBy(int id)
        {
            return UnitOfWork.DbContext.Get<TEntity>(id);
        }

        public bool TryFindBy(ref TEntity result, int id)
        {
            try
            {
                result = FindBy(id);
                if (result == null)
                    throw new Exception();
                return true;
            }
            catch
            {
                return false;
            }
        }

        #endregion
    }
}
